use anyhow::{Context, Result};
use futures::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tokio::net::TcpStream;
use tokio_util::codec::{Framed, LinesCodec};
use tracing::{debug, info};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ESLMessage {
    pub headers: HashMap<String, String>,
    pub body: String,
}

impl ESLMessage {
    pub fn new() -> Self {
        Self {
            headers: HashMap::new(),
            body: String::new(),
        }
    }

    pub fn add_header(&mut self, key: &str, value: &str) {
        self.headers.insert(key.to_string(), value.to_string());
    }

    pub fn get_header(&self, key: &str) -> Option<&String> {
        self.headers.get(key)
    }

    pub fn get_event_name(&self) -> Option<&String> {
        self.get_header("Event-Name")
    }

    pub fn get_uuid(&self) -> Option<&String> {
        self.get_header("Unique-ID")
    }

    pub fn to_string(&self) -> String {
        let mut result = String::new();
        for (key, value) in &self.headers {
            result.push_str(&format!("{}: {}\n", key, value));
        }
        if !self.body.is_empty() {
            result.push_str(&format!("\n{}", self.body));
        }
        result
    }
}

pub struct ESLConnection {
    stream: Framed<TcpStream, LinesCodec>,
}

impl ESLConnection {
    pub async fn connect(host: &str, port: u16) -> Result<Self> {
        let addr = format!("{}:{}", host, port);
        let stream = TcpStream::connect(&addr).await
            .with_context(|| format!("无法连接到FreeSWITCH服务器: {}", addr))?;
        
        let framed = Framed::new(stream, LinesCodec::new());
        Ok(Self { stream: framed })
    }

    pub async fn authenticate(&mut self, password: &str) -> Result<()> {
        let auth_cmd = format!("auth {}\n\n", password);
        self.stream.send(&auth_cmd).await
            .context("发送认证命令失败")?;

        let response = self.stream.next().await
            .ok_or_else(|| anyhow::anyhow!("连接已关闭"))?
            .context("读取认证响应失败")?;

        debug!("认证响应: {}", response);
        
        if response.contains("+OK") {
            info!("认证成功");
            Ok(())
        } else {
            Err(anyhow::anyhow!("认证失败: {}", response))
        }
    }

    pub async fn send_command(&mut self, command: &str) -> Result<ESLMessage> {
        let cmd = format!("{}\n\n", command);
        self.stream.send(&cmd).await
            .context("发送命令失败")?;

        let mut message = ESLMessage::new();
        let mut in_body = false;
        let mut body_lines = Vec::new();

        while let Some(line) = self.stream.next().await {
            let line = line.context("读取响应行失败")?;
            
            if line.is_empty() {
                in_body = true;
                continue;
            }

            if in_body {
                body_lines.push(line.clone());
            } else {
                if let Some((key, value)) = line.split_once(": ") {
                    message.add_header(key, value);
                }
            }

            // 检查是否是消息结束
            if in_body && line.is_empty() {
                break;
            }
        }

        message.body = body_lines.join("\n");
        Ok(message)
    }

    pub async fn read_event(&mut self) -> Result<Option<ESLMessage>> {
        let mut message = ESLMessage::new();
        let mut in_body = false;
        let mut body_lines = Vec::new();
        let mut has_content = false;

        while let Some(line) = self.stream.next().await {
            let line = line.context("读取事件行失败")?;
            has_content = true;
            
            if line.is_empty() {
                in_body = true;
                continue;
            }

            if in_body {
                body_lines.push(line.clone());
            } else {
                if let Some((key, value)) = line.split_once(": ") {
                    message.add_header(key, value);
                }
            }

            // 检查是否是消息结束
            if in_body && line.is_empty() {
                break;
            }
        }

        if has_content {
            message.body = body_lines.join("\n");
            Ok(Some(message))
        } else {
            Ok(None)
        }
    }
} 